﻿
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

#include "CmdGStyleViewer.h"
#include "IUiView.h"
#include "IAction.h"
#include "IElement.h"
#include "IDocument.h"
#include "ElementId.h"
#include "ICategory.h"
#include "ISelection.h"
#include "IModelView.h"
#include "ActionBase.h"
#include "IUiDocument.h"
#include "IPickFilter.h"
#include "IPickTarget.h"
#include "UniIdentity.h"
#include "IHighlights.h"
#include "IDirectShape.h"
#include "IGenericElement.h"
#include "GcmpCommandState.h"
#include "IUserTransaction.h"
#include "ICategoryLibrary.h"
#include "CommandParameters.h"
#include "IElementModelShape.h"
#include "UiDocumentViewUtils.h"
#include "IUiDocumentViewManager.h"
#include "IGraphicsNodeReference.h"
#include "IPickNodeReferenceAction.h"
#include "IGraphicsStyleDataValiditySettings.h"

#include "GRepModule.h"
#include <unordered_set>
#include "GRepCommandIds.h"
#include "CommandRegister.h"
#include "GraphicsStyleDlg.h"
#include "GStyleViewerUtils.h"
#include "GRepProbe\GRepProbe.h"
#include "CmdGStyleModuleEntry.h"
#include "GRepProbe\GRepProbeDlg.h"
#include "GRepProbe\GNodeWrapper.h"
#include "ICanvas.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

using namespace gcmp;
using namespace Sample;

namespace
{
    // 【显示样式探针】命令启动后，拾取图形节点的过滤器，对应Ribbon菜单的checkbox
    class GStyleViewerPickFilter : public IPickFilter
    {
    public:
        virtual bool AllowElement(const ElementId& elementId) const override
        {
            return true;
        }

        virtual bool AllowGraphicsNode(const IGraphicsNodeReference& graphicsNodeReference) const override
        {
            return true;
        }

        virtual bool SetPickTargetOption(IPickTarget* pPickTarget) override
        {
            CmdGStyleModuleEntry::SetPickTarget(pPickTarget);
            return true;
        }
    };

    // 【显示样式探针】和【节点树样式探针】的公共实现函数
    bool ExecuteInternal(gcmp::ElementId& elemId, const gcmp::IGraphicsNode* pGNode, bool canGNodeModifyGStyle, OwnerPtr<IGraphicsElementShape> opCachedGRep = nullptr)
    {
        IUiDocumentViewManager* pUiDocViewManager = IUiDocumentViewManager::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pUiDocViewManager, L"无效的pUiDocViewManager指针",L"GDMP",L"2024-03-30");
        IUiDocument* pUIDoc = pUiDocViewManager->GetCurrentUiDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pUIDoc, L"pUIDoc为空",L"GDMP",L"2024-03-30");
        IDocument* pDoc = pUIDoc->GetDbDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc != nullptr, L"无效的文档指针",L"GDMP",L"2024-03-30");
        IUiView* pCurrentView = pUiDocViewManager->GetCurrentUiView();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurrentView != nullptr, L"无效的当前视图",L"GDMP",L"2024-03-30");

        // 创建显示样式修改的工具类，该工具类会按照样式重载机制获得和设置输入图形节点/图元的显示样式
        OwnerPtr<GStyleViewerUtils> opGStyleViewerUtils = NEW_AS_OWNER_PTR(GStyleViewerUtils, pCurrentView, elemId, pGNode);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opGStyleViewerUtils, L"opGStyleViewerUtils为空",L"GDMP",L"2024-03-30");

        IElement* pElem = pDoc->GetElement(elemId);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pElem, L"pElem为空",L"GDMP",L"2024-03-30");

        // 获得用于在UI上显示和修改的图形节点重载数据
        std::vector<OwnerPtr<GraphicsOverrideData>> opGOverrideDataList = TransferOwnership(opGStyleViewerUtils->GetGStyles(canGNodeModifyGStyle));

        // 创建和显示图形节点重载的对话框
        std::wstring dlgTitle = L"显示样式重载机制设置";
        Sample::GraphicsStyleDlg dlg(pUIDoc, pCurrentView, dlgTitle, opGOverrideDataList);
        if (dlg.exec() != QDialog::Accepted)
        {
            return false;
        }

        // 将UI中修改的图形节点样式重载数据设置到GDMP
        OwnerPtr<IUserTransaction> opUT(IUserTransaction::Create(pDoc, L"样式重载"));
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opUT, L"opUT为空",L"GDMP",L"2024-03-30");
        opGStyleViewerUtils->SetGStyles(TransferOwnership(opGOverrideDataList), canGNodeModifyGStyle, TransferOwnership(opCachedGRep));
        opUT->Commit();

        pCurrentView->GetCanvas()->Refresh();
        return true;
    }
}

//【模型图形表达探针】命令的Action
class GStyleViewerPickAction : public gcmp::ActionBase
{
public:
    GStyleViewerPickAction()
    {}

    virtual void InitAction(IUiView* pCurrentView) override
    {
        // 拾取图形节点
        PickNodeReferenceExchangeData pickNodeRefData(true, &m_pickedReferences);
        OwnerPtr<GStyleViewerPickFilter> opPickFilter = NEW_AS_OWNER_PTR(GStyleViewerPickFilter);
        gcmp::OwnerPtr<IAction> opPickAction = IPickNodeReferenceAction::Create(pickNodeRefData, TransferOwnership(opPickFilter));
        StartChildAction(TransferOwnership(opPickAction));
    }

    virtual void OnChildActionFinished(IUiView* pCurrentView, const ActionOutput& childActionReturnParam) override
    {
        if (m_pickedReferences.size() == 0)
        {
            MarkFinishStatus(ActionFinishStatus::Cancelled);
            return;
        }
        OwnerPtr<IGraphicsNodeReference> opGNodeRef = TransferOwnership(*m_pickedReferences.begin());
        DBG_WARN_AND_RETURN_VOID_UNLESS(opGNodeRef, L"opGNodeRef为空",L"GDMP",L"2024-03-30");
        ElementId elemId = opGNodeRef->GetElementId();

        // 显示和设置显示样式重载数据。目前没有判断拾取的图形节点是否是模型图形节点，因此可能对图形节点的直接设置会不起作用
        ExecuteInternal(opGNodeRef->GetElementId(), opGNodeRef->GetUntransformedIntersectGraphicsNode(), true);

        MarkFinishStatus(ActionFinishStatus::Successful);
    }
private:
    gcmp::GraphicsNodeReferenceOwnerPtrVector m_pickedReferences;
};

//【模型图形表达探针】命令
REGISTER_COMMAND(CmdGStyleViewer)

Sample::CmdGStyleViewer::CmdGStyleViewer()
    : CommandBase(ID_CMD_GSTYLE_VIEWER)
{
}

bool Sample::CmdGStyleViewer::IsEnabled() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

bool Sample::CmdGStyleViewer::IsVisible() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

gcmp::OwnerPtr<gcmp::IAction> Sample::CmdGStyleViewer::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    OwnerPtr<GStyleViewerPickAction> opAction = NEW_AS_OWNER_PTR(GStyleViewerPickAction);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opAction, L"opAction为空",L"GDMP",L"2024-03-30");
    return TransferOwnership(opAction);
}

// 【节点树样式探针】命令
REGISTER_COMMAND(CmdGStyleTreeViewer)

Sample::CmdGStyleTreeViewer::CmdGStyleTreeViewer()
    : CommandBase(ID_CMD_GSTYLE_VIEWER_TREE)
{
}

bool Sample::CmdGStyleTreeViewer::IsEnabled() const
{
    if (!GcmpCommandState::IsInDocumentEnvironment())
    {
        return false;
    }
    GrepProbeDlg* dlg = GrepProbeDlg::Get();
    if (!dlg)
    {
        return false;
    }
    // GRep探针浏览器中需要有选中的节点
    return dlg->GetSelectedGNode() != nullptr;
}

bool Sample::CmdGStyleTreeViewer::IsVisible() const
{
    return GcmpCommandState::IsInDocumentEnvironment();
}

gcmp::OwnerPtr<gcmp::IAction> Sample::CmdGStyleTreeViewer::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    GrepProbeDlg* pGrepProbeDlg = GrepProbeDlg::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGrepProbeDlg, L"pGrepProbeDlg为空",L"GDMP",L"2024-03-30");
    if (!pGrepProbeDlg)
    {
        return nullptr;
    }
    // 获得GRep探针浏览器中选中的节点
    IGraphicsNode* pGNode = pGrepProbeDlg->GetSelectedGNode();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGNode, L"pGNode为空",L"GDMP",L"2024-03-30");
    ElementId elemId = pGrepProbeDlg->GetElementId();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(elemId.IsValid(), L"elemId不合法",L"GDMP",L"2024-03-30");
    IGraphicsNode_Wrapper* pGNode_Wrapper = pGrepProbeDlg->GetDisplayData();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGNode_Wrapper, L"pGNode_Wrapper为空",L"GDMP",L"2024-03-30");

    if (pGNode_Wrapper->IsReadOnly())
    {
        ExecuteInternal(elemId, pGNode, false);
    }
    else // 图形节点的显示样式可能被修改，因此需要更新GRep探针浏览器和GRep浏览器的显示内容
    {
        OwnerPtr<IGraphicsElementShape> opCachedGRep = pGNode_Wrapper->GetCachedGRep();
        ExecuteInternal(elemId, pGNode, true, TransferOwnership(opCachedGRep));

        IUiDocumentViewManager* pUiDocViewManager = IUiDocumentViewManager::Get();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDocViewManager, L"无效的pUiDocViewManager指针",L"GDMP",L"2024-03-30");

        IUiDocument* pUIDoc = pUiDocViewManager->GetCurrentUiDocument();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUIDoc, L"pUIDoc为空",L"GDMP",L"2024-03-30");
        IDocument* pDoc = pUIDoc->GetDbDocument();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc != nullptr, L"无效的文档指针",L"GDMP",L"2024-03-30");

        // GRep更新到GRep探针浏览器和GRep浏览器
        GRepProbe* pGRepProbe = GRepProbe::Get();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGRepProbe, L"pGRepProbe",L"GDMP",L"2024-03-30");
        pGRepProbe->Execute(false, pDoc, elemId);
    }
    return nullptr;
}

